namespace SimpleWebServices.Web
{
    using System;
    using System.Web;
    using System.Xml;
    using System.Xml.XPath;
    using SimpleWebServices;
    using SimpleWebServices.Data;
    using SimpleWebServices.Security.Cryptography;
    using SimpleWebServices.Web.UI.Html;
    using SimpleWebServices.Web.UI.Html.Elements;
    using Xunit;

    public sealed class ResourceFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<Resource>()
                .DerivesFrom<SimpleWebServices.Data.Record>()
                .IsAbstractBaseClass()
                .Implements<IResource>()
                .Result);
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new TestResource() as Resource);
        }

        [Fact]
        public void deserialize()
        {
            TestResource obj = (
                "<resource" +
                    " description='Description text.'" +
                    ">" +
                    "<data><value name='foo'>bar</value></data>" +
                "</resource>").Deserialize<TestResource>();

            Assert.Equal<string>("bar", obj.Data["foo"]);
            Assert.Equal<string>("Description text.", obj.Description);
        }

        [Fact]
        public void deserializeEmpty()
        {
            TestResource obj = "<resource />".Deserialize<TestResource>();

            Assert.Equal<int>(0, obj.Data.Count);
            Assert.Null(obj.Description);
        }

        [Fact]
        public void serialize()
        {
            TestResource obj = new TestResource
            {
                Data = new DataCollection { { "foo", "bar" } },
                Description = "Description text.",
                Links = new LinkCollection { new Link { Relationship = "canonical", Hyperlink = new Uri("http://example.com/page.en.html") } }
            };

            XPathNavigator navigator = obj.Serialize().CreateNavigator();
            XmlNamespaceManager namespaces = new XmlNamespaceManager(navigator.NameTable);
            namespaces.AddNamespace("xml", "http://www.w3.org/XML/1998/namespace");

            Assert.True((bool)obj.Serialize().CreateNavigator().Evaluate("1=count(/resource[@description='Description text.'])", namespaces));
            Assert.True((bool)obj.Serialize().CreateNavigator().Evaluate("1=count(/resource/data/value[@name='foo'][text()='bar'])", namespaces));
        }

        [Fact]
        public void prop_Data()
        {
            Assert.True(new PropertyExpectations(typeof(TestResource).GetProperty("Data"))
                .XmlElement("data")
                .TypeIs<DataCollection>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void prop_Cacheability()
        {
            Assert.True(new PropertyExpectations(typeof(TestResource).GetProperty("Cacheability"))
                .XmlIgnore()
                .TypeIs<HttpCacheability?>()
                .DefaultValueIs(HttpCacheability.Public)
                .Result);
        }

        [Fact]
        public void prop_Etag()
        {
            Assert.True(new PropertyExpectations(typeof(TestResource).GetProperty("Etag"))
                .XmlIgnore()
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_Expires()
        {
            Assert.True(new PropertyExpectations(typeof(TestResource).GetProperty("Expires"))
                .XmlIgnore()
                .IsAutoProperty<Expiration>()
                .Result);
        }

        [Fact]
        public void prop_Description()
        {
            Assert.True(new PropertyExpectations(typeof(TestResource).GetProperty("Description"))
                .XmlAttribute("description")
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void prop_Entity()
        {
            Assert.True(new PropertyExpectations(typeof(TestResource).GetProperty("Entity"))
                .XmlIgnore()
                .TypeIs<string>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void prop_Entity_get()
        {
            TestResource obj = (
                "<resource" +
                    " description='Description text.'" +
                    ">" +
                    "<data><value name='foo'>bar</value></data>" +
                "</resource>").Deserialize<TestResource>();

            string expected = "v7iOgT2IYQaz8Rm7KC6W1w==";
            string actual = MD5Hash.Compute(obj.Entity);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void prop_Entity_getEmpty()
        {
            string expected = string.Empty;
            string actual = new TestResource().Entity;

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void prop_Links()
        {
            Assert.True(new PropertyExpectations(typeof(TestResource).GetProperty("Links"))
                .XmlElement("links")
                .TypeIs<LinkCollection>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void prop_Metadata()
        {
            Assert.True(new PropertyExpectations(typeof(TestResource).GetProperty("Metadata"))
                .XmlElement("metadata")
                .TypeIs<MetaCollection>()
                .DefaultValueIsNotNull()
                .Result);
        }
    }
}